/*
 * @Author: 杰编程 2306248989@qq.com
 * @Date: 2023-07-28 21:26:39
 * @LastEditors: 杰编程 2306248989@qq.com
 * @LastEditTime: 2023-07-28 22:32:32
 * @FilePath: /lesson21/2. cp/blockQueue.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>

const int N=5;

template<class T>
class BlockQueue
{
private:
    void lock()
    {
        pthread_mutex_lock(&_mutex);
    }
    void unlock()
    {
        pthread_mutex_unlock(&_mutex);
    }
    bool isFull()
    {
        return _q.size()==_capacity;
    }
    bool isEmpty()
    {
        return _q.empty();
    }
    
    void pthreadWait(pthread_cond_t& cond)
    {
        pthread_cond_wait(&cond,&_mutex);
    }

    void pthreadWakeUp(pthread_cond_t& cond)
    {
        pthread_cond_signal(&cond);
    }

public:
    BlockQueue(const int num=N):_capacity(num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_comsumer,nullptr);
        pthread_cond_init(&_producer,nullptr);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_comsumer);
        pthread_cond_destroy(&_producer);
    }

    void push(const T& task)
    {
        lock();
        while(isFull())//保证任何时候，要生产时仓库有空余
        {
            pthreadWait(_producer);
        }
        //向仓库运数据
        _q.push(task);
        //有了产品，唤醒消费者消费
        pthreadWakeUp(_comsumer);
        unlock();
    }

    void pop(T* out)
    {
        lock();
        while(isEmpty())
        {
            pthreadWait(_comsumer);
        }
        //仓库有产品，开始消费
        *out=_q.front();
        _q.pop();
        //消费完产品，仓库有空余，唤醒生产者生产
        pthreadWakeUp(_producer);
        unlock();
    }

private:
    std::queue<T> _q;//队列存储数据，被多线程看到，需要被保护
    int _capacity;
    pthread_mutex_t _mutex;//保护队列,一个锁，一个共享资源，就可以保证互斥关系的成立
    //两个条件变量，保证消费者和生产者之间的同步关系
    pthread_cond_t _comsumer;//控制消费速度
    pthread_cond_t _producer;//控制生产速度
};
